"""
jackson.debug

Functions for conditionally printing debug statements

svn update "/home/paniag/workspace/CS 145 CDN Take 1/" -r HEAD --force
"""
import sys
import datetime
from django.conf import settings

file = sys.stderr
nesting = 0

def pre_import(module_name, verbosity=1):
    """
    To be called in a file before imports are made.
    @param module_name: usually just pass __name__
    @param verbosity: usually just leave this out
    """
    # check the PRINT setting in the settings.py file
    cond = settings.PRINT['IMPORTS']
    # compare given verbosity with the VERBOSITY setting in the settings.py file
    cond = cond and settings.VERBOSITY >= verbosity
    if cond:
        line = '\n' + indent() + str(datetime.datetime.now())[11:-7] + '*** '
        line = line + module_name + ': '
        line = line + 'Starting imports'
        print >> file, line

def importing(module_name, message, verbosity=1):
    """
    To be called for every import. A helpful message would be
    @param module_name: usually just pass __name__
    @param message: something descript about the import. Usually, "function1, function2 from module", or just "module"
    @param verbosity: use 1 for any code that part of the project, 2 for third party modules, and 3 for standard python stuff. The default is 1.
    """
    # check the PRINT setting in the settings.py file
    cond = settings.PRINT['IMPORTS']
    # compare given verbosity with the VERBOSITY setting in the settings.py file
    cond = cond and settings.VERBOSITY >= verbosity
    if cond:
        line = '\n' + str(datetime.datetime.now())[11:-7] + '*** '
        line = line + module_name + ': '
        line = line + message
        print >> file, line

def post_import(module_name, verbosity=1):
    """
    To be called in a file right after imports are made.
    @param module_name: usually just pass __name__
    @param verbosity: usually just leave this outs
    """
    # check the PRINT setting in the settings.py file
    cond = settings.PRINT['IMPORTS']
    # compare given verbosity with the VERBOSITY setting in the settings.py file
    cond = cond and settings.VERBOSITY >= verbosity
    if cond:
        line = '\n' + indent() + str(datetime.datetime.now())[11:-7] + '*** '
        line = line + module_name + ': '
        line = line + 'Done with imports'
        print >> file, line

### Execution flow
# context = [module_name, function_name]

def enter(context, args, verbosity=1):
    """
    Used to notify the debug framework that a new context is being entered,
    i.e., we're pushing another context onto the call stack.
    @param context: a list formatted as [module_name, function_name]
    @param args: a dictionary of the arguments that are being passed into the new context, i.e., function parameters
    @param verbosity: the lower the number (min=1), the more crucial this debug info is.
    """
    # nesting keeps track of stack depth on the call stack
    global nesting
    # check the PRINT setting in the settings.py file
    cond = settings.PRINT['CALLS']
    # compare given verbosity with the VERBOSITY setting in the settings.py file
    cond = cond and settings.VERBOSITY >= verbosity
    if cond:
        line = '\n' + indent() + '>>> ' + str(datetime.datetime.now())[11:-7] 
        line = line + ': Entering ' + context[0] + '.' + context[1]
        if not (args == None):
            names = args.keys()
            names.sort()
            for name in names:
                line = line + '\n' + indent(1) + name + ': ' + str(args[name])
        print >> file, line
        # increment nesting appropriately
        nesting = nesting + 1

def comment(context, message, verbosity=1):
    """
    Used to print out a general comment at any point during execution.
    @param context: the context for where the comment is being made. Generally unused in output. Formatted as [module_name, function_name].
    @param message: the comment to be printed.
    @param verbosity: the lower the number (min=1), the more curcial this debug info is
    """
    # check the PRINT setting in the settings.py file
    cond = settings.PRINT['COMMENTS']
    # compare given verbosity with the VERBOSITY setting in the settings.py file
    cond = cond and settings.VERBOSITY >= verbosity
    if cond:
        line = indent() + str(datetime.datetime.now())[11:-7] + ": "
        line = line + message
        print >> file, line

def exception(context, message):
    """
    Used to notify that an exception occurred. Can be used anywhere in execution.
    @param context: the context where the exception occurred. Formatted as [module_name, function_name].
    @param message: the message regarding the exception.
    """
    # check the PRINT setting in the settings.py file
    cond = settings.PRINT['EXCEPTIONS']
    if cond:
        line = '\n' + indent() + str(datetime.datetime.now())[11:-7] + '!!! '
        line = line + context[0] + '.' + context[1] + ': '
        line = line + 'Exception: ' + message
        print >> file, line

def leave(context, vals, verbosity=1):
    """
    Used to notify the debug framework that we are leaving the current context,
    i.i, we're popping the top context off the call stack.
    @param context: a list formatted as [module_name, function_name].
    @param vals: the values the current context is returning.
    @param verbosity: the lower the number (min=1), the more curcial this debug info is
    """
    # nesting keeps track of stack depth on the call stack
    global nesting
    # check the PRINT setting in the settings.py file
    cond = settings.PRINT['CALLS']
    # compare given verbosity with the VERBOSITY setting in the settings.py file
    cond = cond and settings.VERBOSITY >= verbosity
    if cond:
        nesting = nesting - 1
        line = indent() +'<<< ' + str(datetime.datetime.now())[11:-7] 
        line = line + ': Leaving ' + context[0] + '.' + context[1]
        if not (vals == None):
            names = vals.keys()
            names.sort()
            for name in names:
                line = line + '\n' + indent(1) + name + ': ' + str(vals[name])
        print >> file, line

def indent(n=0):
    """Generates the proper amount of indentation for the current nesting.
    @param n: optional extra spacing to be added to the current nesting
    """
    # nesting keeps track of stack depth on the call stack
    global nesting
    ind = ''
    for n in range(0, nesting + n):
        # gets the proper format of indentatino from PRINT in the settings.py file
        ind = ind + settings.PRINT['INDENT']
    return ind
